#!/usr/bin/python
"""
General usage functions and classes.
"""
import os
import sys
import time
import itertools
import subprocess

# By default, verbose level is set the lowest value (print only errors)
verbose_level = 0

# Default verbose levels
ERROR = 0
WARNING = 1
DEBUG = 2

class Struct:
    """Struct/record-like class"""
    def __init__(self, **entries):
        self.__dict__.update(entries)

    def __repr__(self):
        args = ('%s=%s' % (k, repr(v)) for (k, v) in vars(self).iteritems())
        return 'Struct(%s)' % ', '.join(args)

def partial_function(callback, *pargs, **pkwargs):
    """Return a partial function to callback."""
    def _wrapper(*args, **kwargs):
        kwargs.update(pkwargs)
        return callback(*(args+pargs), **kwargs)
    return _wrapper

def flatten(it):
    """Flatten items in iterator."""
    return [x for y in it for x in y]

def first(it, pref=bool):
    """Return first element in iterator that matches the predicate."""
    for item in it:
        if bool(item):
            return item

def itrue(it, pred=bool):
    """Return true values in iterator.""" 
    return itertools.ifilter(pred, it)
    
def _debug(line, channel=sys.stderr):
    """Write line to standard error."""
    channel.write(str(line) + "\n")
    channel.flush()
    
def debug(level, line, channel=sys.stderr):
    """Write a line debug if level is below or equal the configured.
    
    Set verbose_level variable in module to set the verbose output.
    """
    if level <= verbose_level:
        _debug(line, channel)
        
def run(command, inputdata=None, **popen_kwargs):
    """Run a command with optional input."""
    kwargs = dict(stdin=subprocess.PIPE, stdout=subprocess.PIPE)
    kwargs.update(popen_kwargs)
    popen = subprocess.Popen(command, **kwargs)
    data, errdata = popen.communicate(input=inputdata)
    if popen.returncode:
    	_debug("command failed: '%s'" % command)
    return popen.returncode, data, errdata

def uniq(it):
    """Yield non-repeated elements in iterator. Allow unhashable keys"""
    seen = []
    for item in it:
        if item not in seen:
            yield item
            seen.append(item)
        
